package main;

import entitaet.Bestellposten;
import entitaet.Bestellung;
import entitaet.Produkt;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class DAO {
    private EntityManagerFactory emf = Persistence.createEntityManagerFactory("Aufgabe11PU");
    private EntityManager em = emf.createEntityManager();

    public void produktAnlegen(String pname, int vk) {
        persist(new Produkt(pname, vk));
    }

    public void bestellungAnlegen(String kunde) {
        persist(new Bestellung(kunde));
    }

    public void produktInBestellungErgaenzen(int bst, int pn, int anz) {
        Bestellung b = em.find(Bestellung.class, bst);
        if(b == null) {
            System.out.println("Keine Bestellung mit dieser NR vorhanden.");
            return;
        }
        
        Produkt p = em.find(Produkt.class, pn);
        if(p == null) {
            System.out.println("Produkt mit dieser NR nicht vorhanden");
            return;
        }
        
        Bestellposten bp = new Bestellposten(anz, b, p);
        b.bestellpostenHinzufuegen(bp);
        p.bestellPostenHinzufuegen(bp);
        merge(b);
    }

    public void produktAusBestellungLoeschen(int bstnr, int pnr) {
        Bestellung b = em.find(Bestellung.class, bstnr);
        if(b == null) {
            System.out.println("Keine Bestellung mit dieser NR vorhanden.");
        }
        
        Bestellposten bp = em.find(Bestellposten.class, pnr);
        if(bp == null) {
            System.out.println("Bestellposten mit dieser NR nicht vorhanden");
            return;
        }
        
        Produkt p = bp.getProdukt(); //hier muss der BP auch gelöscht werden
        
        //Aus Bestellungen löschen
        b.bestellpostenLoeschen(bp);
        
        //Aus Produkte löschen
        p.BestellPostenLoeschen(bp);
        
        merge(b);
    }

    public void produkteAnzeigen() {
        for(Produkt p : em.createQuery("SELECT p FROM Produkt p", 
                Produkt.class).getResultList()) {
            System.out.println("Nr: " + p.getProduktNr()
                    + ", Name: " + p.getName() + ", Preis: " 
                    + p.getVerkaufsPreis());
        }
    }

    public void bestellungenAnzeigen() {
        for(Bestellung b : em.createQuery("SELECT b FROM Bestellung b", 
                Bestellung.class).getResultList()) {
            System.out.println("-------------------------");
            System.out.println("Nr: " + b.getBestellungsNr()
                    + ", Kunde: " + b.getKundenName());
            
            System.out.println("Artikel:");
            for(Bestellposten bp : b.getBestellposten()) {
                System.out.println(bp.getAnzahl() + " * " + bp.getProdukt().getName());
            }
        }
    }

    public void produktbestellungshaeufigkeiten() {
        Query query = em.createQuery("SELECT p.name, COUNT(b) "
                + "FROM Bestellposten bp, Produkt p, Bestellung b "
                + "WHERE bp.produkt = p AND bp.bestellung = b "
                + "GROUP BY p.name");
        Collection erg = query.getResultList();
        
        for(Iterator it = erg.iterator(); it.hasNext();) {
            Object o = it.next();
            if(o.getClass().getName().equals("[Ljava.lang.Object;")) {
                Object oa[] = (Object[]) o;
                for(int i=0; i<oa.length; i+=2) {
                    System.out.println(oa[i] + ": " + oa[i+1]);
                }
            } else {
                System.out.println("Unerwartete Query-Rückgabe");
            }
        }
    }

    public void nieBestellteProdukte() {
        
        Query query = em.createQuery("SELECT p "
                + "FROM Produkt p, Bestellposten bp "
                + "WHERE NOT EXISTS "
                + "(SELECT p2 FROM Produkt p2 WHERE bp.produkt = p)");
        List erg = query.getResultList();
        
        for(Object o : erg) {
            if(o.getClass().getName().equals("entitaet.Produkt")) {
                System.out.println(o);
            } else {
                System.out.println("Unerwarte Query-Rückgabe");
            }
        }
    }

    /* Hier werden noch keine Einträge ohne Bestellposten berücksichtigt, sonst ok */
    public void bestellsummenBerechnen() {
        
        //Für alle Bestellungen mit vorhandenen Bestellposten
        Query query = em.createQuery("SELECT b.bestellungsNr, p.produktNr, p.verkaufsPreis, bp.anzahl "
                + "FROM Produkt p, Bestellposten bp, Bestellung b "
                + "WHERE bp.produkt = p AND bp.bestellung = b ");
        
        //Und für solche ohne irgendwelche Bestellposten
        Query query2 = em.createQuery("SELECT b.bestellungsNr "
                + "FROM Bestellung b, Bestellposten bp "
                + "WHERE NOT EXISTS "
                + "(SELECT b2 FROM Bestellung b2 WHERE bp.bestellung = b)");
        List erg = query.getResultList();
        List erg2 = query2.getResultList();
        
        //Zuordnung von BestNr -> Summe
        HashMap<Integer, Integer> values = new HashMap<>();
        
        
        for(Object o : erg) {
            if(o.getClass().getName().equals("[Ljava.lang.Object;")) {
                Object oa[] = (Object[]) o;
                
                //Falls es noch keinen Eintrag gibt, einen Wert mit Summe 0 anlegen
                if(values.get((int)oa[0]) == null) {
                    values.put((int)oa[0], 0);
                }
                int summe = values.get((int)oa[0]);
                summe += (int)oa[2] * (int)oa[3];
                values.put((int)oa[0], summe);
            } else {
                System.out.println("Unerwartete Query-Rückgabe");
            }
        }
        
        for(Map.Entry<Integer, Integer> entry : values.entrySet()) {
            System.out.println("BestNr: " + entry.getKey() + ", Summe: " + entry.getValue());
        }
        
        //Ausgabe der leeren Bestellungen
        for(Object o : erg2) {
            if(o.getClass().getName().equals("java.lang.Integer")) {
                System.out.println("BestNr: " + o + ", Summe: " + 0);
                
            }
            
        }
    }

    void startdaten() {
        
        //3 Produkte hinzufügen
        String[] produktNamen = {"Shampoo", "Socken", "Handtuch"};
        int[] produktPreise = {5, 2, 6};
        for(int i=0; i<produktNamen.length; i++) {
            produktAnlegen(produktNamen[i], produktPreise[i]);
        }            
        
        //3 Bestellungen hinzufügen
        String[] kundenNamen = { "Hans", "Hugo", "Frank" };
        for(int i=0; i<kundenNamen.length; i++) {
            bestellungAnlegen(kundenNamen[i]);
        }
        
        //3 Bestellposten anlegen und mit Produkten und Bestellungen verknüpfen
        int[] anzahlBP = { 3, 2, 1};
        List<Produkt> produkteBP = 
                em.createQuery("SELECT p FROM Produkt p", Produkt.class)
                .getResultList();
        List<Bestellung> bestellungBP = 
                em.createQuery("SELECT b FROM Bestellung b", Bestellung.class)
                .getResultList();
        for(int i=0; i<bestellungBP.size(); i++) {
            produktInBestellungErgaenzen(
                    bestellungBP.get(i).getBestellungsNr(),
                    produkteBP.get(i).getProduktNr(),
                    anzahlBP[i]);
        }
    }

    /* freiwillig
     * Ausfuehrung der Anfrage ql, fuer die eine "normale" Liste von
     * Objekten als Ergebnis erwartet wird. */
    public void anfragen(String ql) {

    }

    /* freiwillig
     * Detailliertere Analyse des Ergebnisses der Anfrage ql, falls
     * Object-Arrays in der Ergebnisliste stehen, werden Elemente der
     * Arrays einzeln ausgegeben. */
    public void anfragen2(String ql) {

    }
    
    private void persist(Object o) {
        em.getTransaction().begin();
        try {
            em.persist(o);
            em.getTransaction().commit();
        } catch(Exception e) {
            if(em.getTransaction().isActive()) {
                em.getTransaction().rollback();
            }
            throw e;
        }
    }
    
    private void merge(Object o) {
        em.getTransaction().begin();
        try {
            em.merge(o);
            em.getTransaction().commit();
        } catch(Exception e) {
            if(em.getTransaction().isActive()) {
                em.getTransaction().rollback();
            }
            throw e;
        }
    }
    
    public void closeConnections() {
        //Schliessen
        if(em != null && em.isOpen()) {
            em.close();
        }
        if(emf != null && emf.isOpen()) {
            emf.close();
        }
    }
}
